/*
 * directoryEntry.c
 *
 *  Created on: 26/10/2011
 *      Author: utn_so
 */

#include "utils.h"
#include "directoryEntry.h"
#include "bootsecto.h"
#include <stdio.h>
#include <stdlib.h>

void printEntry(directoryEntry entry){

	printf("el nombre es, %s\n",entry.name);
	printf("el atributo es, %d\n",entry.attribute);
	printf("el tiempo de creacion (fino) es, %d\n",entry.createTimeFine);
	printf("el tiempo de creacion es, %d y %d\n",entry.createTime[0],entry.createTime[1]);
	printf("la fecha de creacion es, %d y %d\n",entry.createDate[0],entry.createDate[1]);
	printf("la ultima fecha de acceso es, %d y %d\n",entry.lastAccessDate[0],entry.lastAccessDate[1]);
	printf("el contenido de la entrada comienza en el cluster: %d\n",entry.firstCluster);
	printf("la ultima hora de modificacion es, %d y %d\n",entry.lastModifiedTime[0],entry.lastModifiedTime[1]);
	printf("la ultima fecha de modificacion es, %d y %d\n",entry.lastModifiedDate[0],entry.lastModifiedDate[1]);
	printf("el size del archivo es:%d bytes \n",entry.fileSize);
	puts("\n");
}


size_t conversion(char *cast,char*utf8){
	size_t size_utf8=0, size_utf16=26;
	uint16_t*utf16= (void*)cast;
	int rta;

	rta= unicode_utf16_to_utf8_inbuffer(utf16,size_utf16,utf8,&size_utf8);

	if(rta==0){
		return strlen(utf8);
	}
	else{
		printf("error en pasaje\n");
		return '\0';
	}
}

void createLongEntry(char *map, unsigned int offset,char **pname){
	int i;
	char *ret,entry[27];
	unsigned char orden,length,j;
	static char utf8[13];

	orden= map[0+offset];

	for (i=1;i<=10;i++){

			entry[i-1] =map[i+ offset];
		}
	for (i=14;i<=25;i++){

			entry[i-4] =map[i+ offset];
		}
	for (i=28;i<=31;i++){

			entry[i-6] =map[i+ offset];
		}


	if ( orden > 64){
		length = conversion(entry,utf8);
		*pname = (char*)malloc(sizeof(char)*length);
		strcpy(*pname,utf8);
		memset(utf8,0,13);
	}
	else {
		entry[26]='\0';

		ret = (char*)malloc(length*sizeof(char));
		strcpy(ret,*pname);

		j= conversion(entry,utf8);
		length = length+j;
		free(*pname);
		*pname = (char*)calloc(length,sizeof(char)*length);
		strcpy(*pname,utf8);

		strcat(*pname,ret);
		free(ret);
		memset(utf8,0,13);
	}
	//printf("nombre largo:%s\n",*pname);
}

void createShortEntry(char *map, unsigned int offset,directoryEntry *entry){

	memset(entry->extension,0,3);


	entry->attribute = map[11 +offset];

	if (entry->attribute==32){
		entry->extension[0] = map[8 +offset];
		entry->extension[1] = map[9 +offset];
		entry->extension[2] = map[10 +offset];
	}


	entry->createTimeFine = map[13 +offset];
	entry->createTime[0] = map[14 +offset];
	entry->createTime[1] = map[15 +offset];

	entry->createDate[0] = map[16 +offset];
	entry->createDate[1] = map[17 +offset];

	entry->lastAccessDate[0] = map[18 +offset];
	entry->lastAccessDate[1] = map[19 +offset];

	entry->lastModifiedTime[0] = map[22 +offset];
	entry->lastModifiedTime[1] = map[23 +offset];

	entry->lastModifiedDate[0] = map[24 +offset];
	entry->lastModifiedDate[1] = map[25+offset];

	char highlow[4]={map[21 +offset],map[20 +offset],map[27+offset],map[26 +offset]};

	entry->firstCluster=concat_uint(highlow,4);

	char size[4]={map[31+offset],map[30+offset],map[29+offset],map[28+offset]};

	entry->fileSize=concat_uint(size,4);

}
//lee un cluster de una entrada de directorio
//y compara el nombre con cada una de las entradas
int processEntry(char *map,NodoEntry **lst,char *name,directoryEntry* entry,unsigned char flag){

	int i=0,j=0,offset=0,enc=-1,sLFN=1;
	//char auxname[8];

		while(i < 128 && enc!=1){ //mientras sea menor que UN cluster y no enc el nombre

			if((map[offset] != 0)&&(map[offset]!=-27)&&(map[offset]!=46)){
				if( map[11 +offset] == 0x0F){ //atributo es LFN

					createLongEntry(map,offset,&entry->name);
					sLFN=0;
				}
				else{
					createShortEntry(map,offset,entry);
					/*
					if (sLFN==1){
						//memset(auxname,0,8);
						while(j<8 && map[j+offset]!=32){
							auxname[j]=map[j+offset];
							j++;
						}
						entry->name=malloc(8*sizeof(char));
						entry->name=strcpy(entry->name,auxname);
					}
					*/

					printEntry(*entry);

					if(flag==1){   //es el directorio que hay que listar, agrego entry a la lista
						add_entry(lst,*entry);
					}
					else{
					enc=strcmp(entry->name,name)+1; //si los nombres coinciden (enc=1), encontro la entrada y la devuelve
					}
					sLFN=1;
				}
			}
			offset+=32;
			i++;
		}
		return enc;
}

//dado el path de un dir (ej:/carpeta) agrega a una lista sus entradas (lst- hola hello.txt..)
//retorna -1 si lo enc, 0 o 2 si no lo enc

int read_directory(char disk,NodoEntry **lst,const char *path,unsigned int rootclus){

	unsigned int j=1,offset,offset_root=0x104000,cont=1;
	int enc=1;
	char**newpath,*map;
	unsigned char flag=0;
	newpath=NULL;
	directoryEntry entry;

	newpath = string_split2(path,'/');

	if((strcmp(path, "/") == 0)){
		newpath[1]=NULL;
	}

	while (newpath[cont]!=NULL){
		cont++;
	}

	offset=offset_root;

	while (cont>=1 && enc==1){
		map = mmap(0,1,PROT_READ ,MAP_PRIVATE, disk,offset);
		if (cont ==1){ //termino el path
			flag=1;
		}
		enc = processEntry(map,lst,newpath[j],&entry,flag);
		offset=4096*((entry.firstCluster)-rootclus)+offset_root;
		//verificar en fat si ocupa mas de 1 cluster
		j++;
		cont--;
	}

	return enc;
}

//dado un path (ej:/carpeta) lee su entrada(arch o dir) y la devuelve (entry- nombre:carpeta atributos:..)
//retorna 1 si encontro la entrada, 0 o 2 si no lo enc

int read_entry(char disk,const char *path,unsigned int rootclus,directoryEntry *entry){
	unsigned int j=1,offset,offset_root=0x104000,cont=1;
		int enc=1,*fat_table;
		char**newpath,*map;
		newpath=NULL;

		newpath = string_split2(path,'/');

		while (newpath[cont]!=NULL){
			cont++;
		}
		fat_table = getFatTable(disk);
		offset=offset_root;
		map = mmap(0,1,PROT_READ ,MAP_PRIVATE, disk,offset);//pedir directorio raiz
		while (cont>1 && enc==1){

			enc = processEntry(map,NULL,newpath[j],entry,0);

			offset=4096*((entry->firstCluster)-rootclus)+offset_root;
			map = mmap(0,1,PROT_READ ,MAP_PRIVATE, disk,offset);

			j++;
			cont--;
		}

		//map = mmap(0,1,PROT_READ ,MAP_PRIVATE, disk, 0x4000);

		/*
		while(map[i]!=entry.firstCluster) {

			printf("%c",map[i]);
			i++;
		}
		*/
		return enc;
}

//lee el cluster numCluster de un path
//retorna el contenido de numCluster (direccion al siguiente cluster), 0 en caso de error
unsigned int clusterDeUnArchivo(char disk,const char*path,unsigned int numCluster){
	directoryEntry entry;
	int enc=0,ret=0,*fat_table;
	unsigned int i;

	if (strcmp(path,"/")!=0){
		enc = read_entry(disk,path,2,&entry);
	}

	if (enc==1){
		fat_table = getFatTable(disk);
		ret =entry.firstCluster;

		for (i=0;i<numCluster;i++){
			ret = fat_table[ret];
		}

	}
	else{
		puts("no existe el path o es /");
	}

	return ret;
}
